﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace 委托
{
    delegate string MyDelegate(float a,float b);//定义一个委托，带有两个传入参数，返回的是一个string类型
   //delegate float MyDelegate(float a, float b);定义一个委托，带有两个传入参数，返回的是一个float类型,
   //注意，不能用返回string类型的去委托public float Mulitple(float a,float b)，会出现异常
    public partial class Form1 : Form
    {
        /// <summary>
        /// 委托的作用：
        /// 1、将方法做为方法的参数进行传递，有利于方法的解耦
        /// 2、声明事件并且用来注册
        /// 3、委托实际上就是委托某人干某件事，MyDelegate myDelegate = new MyDelegate(meth1)委托myDelegate去干meth1这件事
        /// 4、必须使用invoke来委托实例，myDelegate.Invoke()
        /// 
        /// 定义委托的格式：
        /// 1、声明委托的类型，带不带返回参数
        /// 2、必须要有一个方法包括了要执行的代码，这个方法必须符合委托类型的签名；
        /// 3、委托和类的type一样，定义委托要定义在类的外面，委托和类同级
        /// 4、要创建一个委托实例
        /// </summary>
 
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            
            string result = myCal(5, 7, Add);//返回一个字符串，传入的参数为5和7，委托myDelegate去干Add这件事
            MessageBox.Show(result);

            string result2 = myCal(3, 40, Mulitple);//返回一个float类型，委托myDelegate去干Mulitple这件事
            MessageBox.Show(result2.ToString());

        }
        /// <summary>
        /// 定义一个算法，该算法传入两个参数a和b，返回的是一个字符串
        /// 在实际应用中，该算法可能是很复杂的算法，比如别人封装好的算法，但是只需要知道传入的算法参数是什么，返回的值是什么
        /// 不关心他的实现过程是怎样
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public string Add(float a, float b)
        {
            return (a + b).ToString();
        }
        public string Mulitple(float a,float b)
        {
            return (a * b).ToString();
        }
        /// <summary>
        /// 定义自己的算法，有传入参数a和b，
        /// ab这两个变量就是委托给外部的接口，具体实现的方法是在myDelegate中
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <param name="myDelegate"></param>
        /// <returns></returns>
        string myCal(float a,float b,MyDelegate myDelegate)
        {
            return myDelegate(a, b);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            ///强类型委托Action
            ///Action<T1>,只有一个参数，没有返回值
            ///Func<T1,T2,T3,TReuslt>，有返回值
            ///调用Action和Func需要使用lamda表达式
            
            Action a1 = () => { MessageBox.Show("我是强类型委托测试"); };//不带参数的Action测试
            a1.Invoke();//调用委托要使用Invoke方法

            Action<string> a2 = (h) => { MessageBox.Show(h); };//传入一个字符串参数h,用a2去调用他
            string g = "abc123456";
            a2.Invoke(g);//把invoke中的字符串传入h中
            
            Action<int> a3 = (h) => { Console.WriteLine(h); };
            a3.Invoke(3 + 4 + 5);//把表达式传入h，使用a3去调用

            ///lamda表达式
            ///（参数列表）=>{方法体}其中“=>”就是Lambda操作符
            ///一个完整的lambda表达式就是一个完整的方法，表达式本身就代表着这个方法的引用，可以被装进委托里

            Func<int, int, string> func = (arg1,arg2) => { return (arg1 + arg2).ToString(); };
            //Func必须有返回参数，上述传入了两个int型参数，返回的是一个string类型的数据
            MessageBox.Show("Func输出"+func.Invoke(4, 6));//func.Invoke(4, 6)----->arg1=4,arg2=6
            //func.Invoke(4, 6);

            //匿名函数的写法
            Func<int, int, string> func1 = delegate (int x, int y) { return (x + y).ToString(); };
            MessageBox.Show("这是匿名函数的用法：" + func1(50, 20).ToString());
        }
    }
}
